#include "utilities.h"

//This include the status request/response processing
void statusProcessing(msg_header msgRespHdr, listBuffStruct eventReq)
{
	map<int,writeListData>::iterator it;
	list<statusSTR>::iterator itR;
	list<fromUOIDStr>::iterator itF;
	//Process the status request accordingly
	if((uint8_t)msgRespHdr.msgtype == 0xAC)
	{
		status_msg tempMsg;
		memcpy(&tempMsg.statustype, &(eventReq.listBuff[27]), sizeof(uint8_t));
		if(printFlag==1)
		{
			cout<<"Got Status Request msg from - "<<eventReq.portNumber<<endl;
		}
		//Find the UOID in the uoid queue and remove if duplicate i.e. if testUOID = 1
		int testUOID = findInUOIDList(msgRespHdr.uoid);
		if(testUOID == 1)
		{
			
		}
		else
		{
			//Put the UOID in uoid queue
			uoidStr tempUOIDStr;
			struct timeval time1;
			gettimeofday(&time1, NULL);
			tempUOIDStr.timeOfTheDay = (double)(time1.tv_sec * 1000 + (double)time1.tv_usec/1000);
			tempUOIDStr.msgLifeTime = initMap["MsgLifetime"];
			memcpy(tempUOIDStr.msgUOID, msgRespHdr.uoid, 20);
			pthread_mutex_lock(&uoidlock);
			myUOIDList.push_back(tempUOIDStr);
			pthread_mutex_unlock(&uoidlock);
			//if TTL is 1 then do not forward
			if(msgRespHdr.timetolive==1)
			{
				
			}
			else
			{
				//Forward the request to neighbors and reduce TTL by 1
				listBuffStruct lbtemp;
				lbtemp.logtype=2;
				int tempTTL = msgRespHdr.timetolive;
				tempTTL--;
				msgRespHdr.timetolive = tempTTL;
				memset(&lbtemp.listBuff, '\0', 27+sizeof(tempMsg));
				fillMsgHdrBuffer(msgRespHdr, lbtemp.listBuff);
				memcpy(&(lbtemp.listBuff[27]),&tempMsg.statustype, sizeof(uint8_t));
				lbtemp.datalength = 27 + sizeof(uint8_t);
				pthread_mutex_lock(&writeMapMutex);
				for(it=writeMap.begin(); it!=writeMap.end(); it++)
				{
					if((*it).first!=eventReq.portNumber)
					{
						//store the uoid in a map so that when it recieves a response then send it to the persone who initiated it.
						fromUOIDStr fromTemp;
						memcpy(fromTemp.uoid, &msgRespHdr.uoid, 20);
						fromTemp.portnumber = eventReq.portNumber;
						myFromUOIDList.push_back(fromTemp);
						lbtemp.portNumber = (*it).first;
						writeListData listDataStr = writeMap[(*it).first];
						listDataStr.response.push_back(lbtemp);
						writeMap[(*it).first] = listDataStr;
					}
				}
				pthread_mutex_unlock(&writeMapMutex);
			}
			//Make the Response and put in write queue
			//1. Make status response
			int dataLen = 0;
			status_response_msg statusRspMsg;
			memcpy(&statusRspMsg.uoid, &msgRespHdr.uoid, 20);
			memset(&statusRspMsg.hostname, '\0', 512);
			memcpy(&statusRspMsg.hostname, hostname, strlen(hostname));
			statusRspMsg.hostport = port_recieve;
			statusRspMsg.hostinfolength = strlen(hostname) + sizeof(uint16_t);
			dataLen = strlen(hostname)+(2*sizeof(uint16_t))+20;
			int tempLeng = 0;
			memset(&statusRspMsg.data, '\0', 512);
			int tempLastStrlen = 0;
			pthread_mutex_lock(&writeMapMutex);
			for(it=writeMap.begin(); it!=writeMap.end(); it++)
			{
					uint32_t len = sizeof(uint16_t) + strlen((*it).second.hostname);
					memcpy(&(statusRspMsg.data[tempLeng]), &len, sizeof(uint32_t));
					uint16_t port = (*it).first;
					memcpy(&(statusRspMsg.data[tempLeng + sizeof(uint32_t)]), &port, sizeof(uint16_t));
					memcpy(&(statusRspMsg.data[tempLeng + sizeof(uint32_t) + sizeof(uint16_t)]), (*it).second.hostname, strlen((*it).second.hostname));
					if(printFlag==1)
					{
						printf("%s\n",&(statusRspMsg.data[tempLeng + sizeof(uint32_t) + sizeof(uint16_t)]));
					}
					tempLeng = tempLeng + sizeof(uint16_t) + sizeof(uint32_t) + strlen((*it).second.hostname);
					tempLastStrlen = sizeof(uint32_t) + sizeof(uint16_t) + strlen((*it).second.hostname);
					if(printFlag==1)
					{
						cout<<"tmepLeng "<<tempLeng<<endl;
					}					
			}
			pthread_mutex_unlock(&writeMapMutex);
		
			uint32_t lastZero = 0;
			dataLen = dataLen + tempLeng;
			memcpy(&(statusRspMsg.data[tempLeng-tempLastStrlen]), &lastZero, sizeof(uint32_t));
			//2. Make header
			char obj[512];
			msg_header responseHdr;
			strcpy(obj,"STRS");
			createMsgHdrStr(&responseHdr,0xAB,initMap["TTL"].asDouble,obj,node_instance_id, dataLen);
			
			//copy the above structures into message response structure
			listBuffStruct lbtemp;
			lbtemp.logtype=1;
			memset(&lbtemp.listBuff, '\0', 27+dataLen);
			fillMsgHdrBuffer(responseHdr, lbtemp.listBuff);

			memcpy(&(lbtemp.listBuff[27]),&(statusRspMsg.uoid),20);
			memcpy(&(lbtemp.listBuff[47]),&(statusRspMsg.hostinfolength),sizeof(uint16_t));
			memcpy(&(lbtemp.listBuff[49]),&(statusRspMsg.hostport),sizeof(uint16_t));
			memcpy(&(lbtemp.listBuff[51]),statusRspMsg.hostname,statusRspMsg.hostinfolength-sizeof(uint16_t));
			memcpy(&(lbtemp.listBuff[51+statusRspMsg.hostinfolength-sizeof(uint16_t)]),statusRspMsg.data,dataLen - 24 - statusRspMsg.hostinfolength + sizeof(uint16_t));
			lbtemp.datalength = 27+dataLen;
			lbtemp.portNumber = eventReq.portNumber;
			pthread_mutex_lock(&writeMapMutex);
			writeListData listDataStr = writeMap[eventReq.portNumber];
			//put them in the writeQueue.
			listDataStr.response.push_back(lbtemp);
			writeMap[eventReq.portNumber] = listDataStr;
			pthread_mutex_unlock(&writeMapMutex);
		}
	}
	
	//Process the status response accordingly
	if((uint8_t)msgRespHdr.msgtype == 0xAB)
	{
		if(printFlag==1)
		{
			cout<<"Got Status Response msg from - "<<eventReq.portNumber<<endl;
		}
		status_response_msg tempMsg;
		memcpy(&(tempMsg.uoid), &(eventReq.listBuff[27]), 20);
		memcpy(&(tempMsg.hostinfolength), &(eventReq.listBuff[47]), sizeof(uint16_t));
		memcpy(&(tempMsg.hostport), &(eventReq.listBuff[49]), sizeof(uint16_t));
		memset(tempMsg.hostname, '\0', 512);
		memcpy(&(tempMsg.hostname), &(eventReq.listBuff[51]), tempMsg.hostinfolength-sizeof(uint16_t));
		memset(tempMsg.data,'\0', 512);
		memcpy(&(tempMsg.data), &(eventReq.listBuff[51+(tempMsg.hostinfolength-sizeof(uint16_t))]), msgRespHdr.datalength-24-tempMsg.hostinfolength+sizeof(uint16_t));
		//If I am the request initiator then store the response onto a .out file
		bool match = false;
		for(itR=statusResponseList.begin(); itR!=statusResponseList.end(); itR++)
				{
					statusSTR temp = *itR;
					if(memcmp(tempMsg.uoid,temp.uoid,20)==0)
					{
					if(printFlag==1)
					{
						cout<<"MATCH FOUND"<<endl;
					}
					match = true;
					break;
					}
				}
		if(match==true)
		{
			if(printFlag==1)
			{
				cout<<"Got from "<<eventReq.portNumber<<endl;
			}
			for(int i=0; i<20; i++)
			{
				if(printFlag==1)
					{
						printf("%02x", (uint8_t)(tempMsg.uoid[i]));
					}
			}
			if(printFlag==1)
			{
				cout<<endl;
				printf("%d\n", tempMsg.hostinfolength);
				printf("%d\n", tempMsg.hostport);
				cout<<tempMsg.hostname<<endl;
			}
			int tempIndex = 0;
			uint32_t tempLeng = -1;
			while(1)
			{
				memcpy(&tempLeng, &tempMsg.data[tempIndex], sizeof(uint32_t));
				if(printFlag==1)
				{
					printf("temp leng - %d\n",tempLeng);
					printf("temp index - %d\n", tempIndex);
				}
				uint16_t datasport;
				char datashost[512];
				if(tempLeng != 0)
				{
					memset(datashost, '\0', 512);
					memcpy(&datasport, &tempMsg.data[tempIndex+sizeof(uint32_t)], sizeof(uint16_t));
					memcpy(&datashost, &tempMsg.data[tempIndex+sizeof(uint32_t)+sizeof(uint16_t)], tempLeng-(sizeof(uint32_t)+sizeof(uint16_t)));
					pthread_mutex_lock(&statusRespLock);
					statusResp.insert(pair<int, int>(tempMsg.hostport, datasport));
					pthread_mutex_unlock(&statusRespLock);
					if(printFlag==1)
					{
						printf("%d\n", datasport);
						printf("%s\n",datashost);
					}
				}
				else
				{
					memset(datashost, '\0', 512);
					memcpy(&datasport, &tempMsg.data[tempIndex+sizeof(uint32_t)], sizeof(uint16_t));
					memcpy(&datashost, &tempMsg.data[tempIndex+sizeof(uint32_t)+sizeof(uint16_t)], msgRespHdr.datalength-24-(sizeof(uint32_t)+sizeof(uint16_t)));
					pthread_mutex_lock(&statusRespLock);
					statusResp.insert(pair<int, int>(tempMsg.hostport, datasport));
					pthread_mutex_unlock(&statusRespLock);
					if(printFlag==1)
					{
						printf("%d\n", datasport);
						printf("%s\n",datashost);
					}
					break;
				}
				tempIndex = tempIndex + tempLeng + sizeof(uint32_t);
			}
		}
		else
		{
			//If I am not the request initiator then send it to the person who requested/forwarded the request
			int testUOID = findInUOIDList(msgRespHdr.uoid);
			if(testUOID == 1)
			{
				
			}
			else
			{
				//Store the request in the uoid queue.
				uoidStr tempUOIDStr;
				struct timeval time1;
				gettimeofday(&time1, NULL);
				tempUOIDStr.timeOfTheDay = (double)(time1.tv_sec * 1000 + (double)time1.tv_usec/1000);
				tempUOIDStr.msgLifeTime = initMap["MsgLifetime"];
				memcpy(tempUOIDStr.msgUOID, msgRespHdr.uoid, 20);
				pthread_mutex_lock(&uoidlock);
				myUOIDList.push_back(tempUOIDStr);
				pthread_mutex_unlock(&uoidlock);
				//If TTL is 1 then do not forward
				if(msgRespHdr.timetolive==1)
				{
			
				}
				else
				{
					//Sending the response to the forwarder
					listBuffStruct lbtemp;
					int tempTTL = msgRespHdr.timetolive;
					if(printFlag==1)
					{
						cout<<"TTL - "<<tempTTL<<endl;
					}
					tempTTL--;
					msgRespHdr.timetolive = tempTTL;
					memset(&lbtemp.listBuff, '\0', eventReq.datalength);
					fillMsgHdrBuffer(msgRespHdr, lbtemp.listBuff);
					memcpy(&(lbtemp.listBuff[27]),tempMsg.uoid,20);
					memcpy(&(lbtemp.listBuff[47]),&(tempMsg.hostinfolength),sizeof(uint16_t));
					memcpy(&(lbtemp.listBuff[49]),&(tempMsg.hostport),sizeof(uint16_t));
					memcpy(&(lbtemp.listBuff[51]),tempMsg.hostname,tempMsg.hostinfolength-sizeof(uint16_t));
					memcpy(&(lbtemp.listBuff[51+tempMsg.hostinfolength-sizeof(uint16_t)]),tempMsg.data,eventReq.datalength - 24 - tempMsg.hostinfolength + sizeof(uint16_t));
					lbtemp.datalength = eventReq.datalength;
					lbtemp.portNumber = eventReq.portNumber;
					lbtemp.logtype=2;
					pthread_mutex_lock(&writeMapMutex);
					
					for(itF=myFromUOIDList.begin(); itF!=myFromUOIDList.end(); itF++)
					{
						fromUOIDStr temp = *itF;
						if(memcmp(tempMsg.uoid,temp.uoid,20)==0)
						{
							writeListData listDataStr = writeMap[temp.portnumber];
							listDataStr.response.push_back(lbtemp);
							writeMap[temp.portnumber] = listDataStr;
							break;
						}
					}
					pthread_mutex_unlock(&writeMapMutex);
				}
			}
		}
	}
}
